package storage

import (
	"context"
	"enzyme-backend/core/models"
	"enzyme-backend/core/utils"
	"fmt"
	"sync"
	"time"

	_ "github.com/golang-migrate/migrate/v4/database/postgres"
	_ "github.com/golang-migrate/migrate/v4/source/file"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

var (
	// GlobalPSQL 全局PostgreSQL存储实例
	GlobalPSQL *PostgresStorage
	psqlOnce   sync.Once
)

// PostgresStorage PostgreSQL存储实现
type PostgresStorage struct {
	db *gorm.DB
}

// PostgresConfig PostgreSQL配置
type PostgresConfig struct {
	Host     string
	Port     string
	User     string
	Password string
	DBName   string
	SSLMode  string
}

func init() {
	psqlOnce.Do(func() {
		// 从环境变量读取PostgreSQL配置
		config := &PostgresConfig{
			Host:     utils.ENV.POSTGRES_HOST,
			Port:     utils.ENV.POSTGRES_PORT,
			User:     utils.ENV.POSTGRES_USER,
			Password: utils.ENV.POSTGRES_PASSWORD,
			DBName:   utils.ENV.POSTGRES_DB,
			SSLMode:  utils.ENV.POSTGRES_SSLMODE,
		}

		// 构建DSN
		dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
			config.Host, config.Port, config.User, config.Password, config.DBName, config.SSLMode)

		// 连接数据库
		db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
		if err != nil {
			utils.GlobalLogger.Error("连接PostgreSQL失败: %v", err)
			return
		}

		// 测试连接
		sqlDB, err := db.DB()
		if err != nil {
			utils.GlobalLogger.Error("获取SQL DB失败: %v", err)
			return
		}

		if err := sqlDB.Ping(); err != nil {
			utils.GlobalLogger.Error("PostgreSQL Ping失败: %v", err)
			return
		}

		// 自动迁移users表
		if err := db.AutoMigrate(&models.UserModel{}); err != nil {
			utils.GlobalLogger.Error("自动迁移users表失败: %v", err)
			return
		}
		utils.GlobalLogger.Info("users表迁移成功")

		// 自动迁移devices表
		if err := db.AutoMigrate(&models.DeviceModel{}); err != nil {
			utils.GlobalLogger.Error("自动迁移devices表失败: %v", err)
			return
		}
		utils.GlobalLogger.Info("devices表迁移成功")

		GlobalPSQL = &PostgresStorage{
			db: db,
		}
		utils.GlobalLogger.Info("PostgreSQL存储已初始化")
	})
}

// GetDB 获取数据库连接
func (ps *PostgresStorage) GetDB() *gorm.DB {
	return ps.db
}

// Close 关闭数据库连接
func (ps *PostgresStorage) Close() error {
	if ps.db != nil {
		sqlDB, err := ps.db.DB()
		if err != nil {
			return err
		}
		return sqlDB.Close()
	}
	return nil
}

// 用户可以只使用指纹登录，也可以使用邮箱密码登录。
// 如果用户使用邮箱密码登录，则返回邮箱对应的token。
// 如果用户使用指纹登录，则返回指纹对应的token。
// 如果用户使用指纹登录，但指纹不存在，则创建指纹及其token。
// 如果用户使用邮箱密码登录，但用户不存在，则返回错误。
// 如果用户使用邮箱密码登录，但密码错误，则返回错误。

var TheBeginOfTheWorld = time.Date(1990, 7, 8, 0, 0, 0, 0, time.UTC)

func (ps *PostgresStorage) LoginForToken(ctx context.Context, fingerprint string, email string, password string) (string, error) {
	if email == "" && password == "" {
		var device models.DeviceModel
		err := ps.db.Where("fingerprint = ?", fingerprint).First(&device).Error
		if err != nil {
			if err == gorm.ErrRecordNotFound {
				device = models.DeviceModel{
					Fingerprint: fingerprint,
					Token:       utils.GenerateHex(16),
					ExpiredAt:   TheBeginOfTheWorld,
				}
				if err := ps.db.Create(&device).Error; err != nil {
					return "", fmt.Errorf("创建指纹失败: %w", err)
				}
				return device.Token, nil
			}
			return "", fmt.Errorf("获取指纹失败: %w", err)
		}
		return device.Token, nil
	}

	var user models.UserModel
	err := ps.db.Where("email = ?", email).First(&user).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return "", fmt.Errorf("用户不存在")
		}
		return "", fmt.Errorf("获取用户失败: %w", err)
	}

	if password != "" && user.Password != password {
		return "", fmt.Errorf("密码错误")
	}

	// 更新或创建设备记录
	var device models.DeviceModel
	err = ps.db.Where("fingerprint = ?", fingerprint).First(&device).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			device = models.DeviceModel{
				Fingerprint: fingerprint,
				Token:       utils.GenerateHex(16),
				ExpiredAt:   TheBeginOfTheWorld,
				UserToken:   user.Token,
			}
			if err := ps.db.Create(&device).Error; err != nil {
				return "", fmt.Errorf("创建设备失败: %w", err)
			}
		} else {
			return "", fmt.Errorf("获取设备失败: %w", err)
		}
	} else {
		device.UserToken = user.Token
		device.ExpiredAt = user.ExpiredAt
		if err := ps.db.Save(&device).Error; err != nil {
			return "", fmt.Errorf("更新设备失败: %w", err)
		}
	}

	return device.Token, nil
}

// VerifyToken 验证token
// 先找user，再找device，如果user和device都不存在，则返回token不合法。
// 如果user存在，则返回token合法。
// 如果device存在，则返回token合法。
func (ps *PostgresStorage) VerifyToken(ctx context.Context, token string) error {
	var user models.UserModel
	err := ps.db.Where("token = ?", token).First(&user).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			var device models.DeviceModel
			err = ps.db.Where("token = ?", token).First(&device).Error
			if err != nil {
				if err == gorm.ErrRecordNotFound {
					return fmt.Errorf("token不合法")
				}
				return fmt.Errorf("验证token失败: %w", err)
			}
			return nil
		}
		return fmt.Errorf("验证token失败: %w", err)
	}
	return nil
}

// CreateUser 创建用户
func (s *PostgresStorage) CreateUser(ctx context.Context, user *models.UserModel) error {
	return s.db.WithContext(ctx).Create(user).Error
}

// GetUserByEmail 通过邮箱获取用户
func (ps *PostgresStorage) GetUserByEmail(ctx context.Context, user *models.UserModel, email string) error {
	err := ps.db.WithContext(ctx).Where("email = ?", email).First(user).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return err
		}
		utils.GlobalLogger.Error("GetUserByEmail: %v", err)
		return err
	}
	return nil
}

// GetUserByToken 通过token获取用户
func (ps *PostgresStorage) GetUserByToken(ctx context.Context, user *models.UserModel, token string) error {
	err := ps.db.WithContext(ctx).Where("token = ?", token).First(user).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return err
		}
		utils.GlobalLogger.Error("GetUserByToken: %v", err)
		return err
	}
	return nil
}

// UpdateUser 更新用户信息
func (ps *PostgresStorage) UpdateUser(ctx context.Context, user *models.UserModel) error {
	user.UpdatedAt = time.Now()
	if err := ps.db.Save(user).Error; err != nil {
		utils.GlobalLogger.Error("UpdateUser: %v", err)
		return err
	}
	return nil
}

// GetDeviceByFingerprint 通过指纹获取设备
func (ps *PostgresStorage) GetDeviceByFingerprint(ctx context.Context, device *models.DeviceModel, fingerprint string) error {
	err := ps.db.WithContext(ctx).Where("fingerprint = ?", fingerprint).First(device).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return err
		}
		utils.GlobalLogger.Error("GetDeviceByFingerprint: %v", err)
		return err
	}
	return nil
}

// GetDeviceByToken 通过token获取设备
func (ps *PostgresStorage) GetDeviceByToken(ctx context.Context, device *models.DeviceModel, token string) error {
	err := ps.db.WithContext(ctx).Where("token = ?", token).First(device).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return err
		}
		utils.GlobalLogger.Error("GetDeviceByToken: %v", err)
		return err
	}
	return nil
}

// CreateDevice 创建设备
func (ps *PostgresStorage) CreateDevice(ctx context.Context, device *models.DeviceModel) error {
	if err := ps.db.WithContext(ctx).Create(device).Error; err != nil {
		utils.GlobalLogger.Error("CreateDevice: %v", err)
		return err
	}
	return nil
}

// UpdateDevice 更新设备信息
func (ps *PostgresStorage) UpdateDevice(ctx context.Context, device *models.DeviceModel) error {
	device.UpdatedAt = time.Now()
	if err := ps.db.WithContext(ctx).Save(device).Error; err != nil {
		utils.GlobalLogger.Error("UpdateDevice: %v", err)
		return err
	}
	return nil
}
